/*
 * JVM_Opcode_branch.c
 *
 *  Created on: 05.01.2011
 *      Author: Tavin
 */
#include <stdint.h>

#include "JVM_StatusCodes.h"
#include "JVM_DataTypes.h"
#include "JVM_Opcode.h"
#include "JVM_OpcodeBranch.h"
#include "JVM_StatusCodes.h"

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_nop									Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.15			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_nop()
{
	return(STCD_OK);
}



#define IF_NULL				0
#define IF_NOT_NULL			1
/****************************************************************************************/
/*																						*/
/*	Function : JVM_isReferenceNull							Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.15			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_isReferenceNull(uint8_t type)
{
	int16_t offset;
	JVM_HandleNumber_t myHandle;

	offset=JVM_Opcode_getCodeShort();
	myHandle=JVM_Opcode_popReference();

	//TODO CHECK FOR NULL REFERENCE ???

	if (((myHandle==HANDLE_NULL) && (type==IF_NULL)) ||
			((myHandle!=HANDLE_NULL) && (type==IF_NOT_NULL)))
		{
		JVM_Opcode_movePC(offset-3);
		}


	return(STCD_OK);
}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_ifnull								Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.15			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_ifnull()
{
/*	int16_t offset;
	JVM_HandleNumber_t myHandle;

	offset=JVM_Opcode_getCodeShort();
	myHandle=JVM_Opcode_popReference();

	if (myHandle==HANDLE_NULL)
		{
		JVM_Opcode_movePC(offset-3);
		}
*/
	return(JVM_isReferenceNull(IF_NULL));
}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_ifnonnull							Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.15			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_ifnonnull()
{
/*	int16_t offset;
	JVM_HandleNumber_t myHandle;

	offset=JVM_Opcode_getCodeShort();
	myHandle=JVM_Opcode_popReference();

	if (myHandle!=HANDLE_NULL)
		{
		JVM_Opcode_movePC(offset-3);
		}
*/
	return(JVM_isReferenceNull(IF_NOT_NULL));
}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_goto_w								Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.4			Status : Working   			*/
/*																						*/
/****************************************************************************************/


uint16_t JVM_cmd_goto_w()
{
	return(STCD_OK);
}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_ifeq									Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.6			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_ifeq()
{
	int16_t offset;
	int32_t value;

	offset=JVM_Opcode_getCodeShort();

	value=JVM_Opcode_popIntValue();

	if (value==0)
		{
		JVM_Opcode_movePC(offset-3);
		}

	return(STCD_OK);
}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_ifne									Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.6			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_ifne()
{
	int16_t offset;
	int32_t value;

	offset=JVM_Opcode_getCodeShort();

	value=JVM_Opcode_popIntValue();

	if (value!=0)
		{
		JVM_Opcode_movePC(offset-3);
		}

	return(STCD_OK);
}
/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_iflt									Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.6			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_iflt()
{
	int16_t offset;
	int32_t value;

	offset=JVM_Opcode_getCodeShort();

	value=JVM_Opcode_popIntValue();

	if (value<0)
		{
		JVM_Opcode_movePC(offset-3);
		}

	return(STCD_OK);
}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_ifge									Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.6			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_ifge()
{
	int16_t offset;
	int32_t value;

	offset=JVM_Opcode_getCodeShort();

	value=JVM_Opcode_popIntValue();

	if (value>=0)
		{
		JVM_Opcode_movePC(offset-3);
		}

	return(STCD_OK);
}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_ifgt									Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.6			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_ifgt()
{
	int16_t offset;
	int32_t value;

	offset=JVM_Opcode_getCodeShort();

	value=JVM_Opcode_popIntValue();

	if (value>0)
		{
		JVM_Opcode_movePC(offset-3);
		}

	return(STCD_OK);
}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_ifle									Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.6			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_ifle()
{
	int16_t offset;
	int32_t value;

	offset=JVM_Opcode_getCodeShort();

	value=JVM_Opcode_popIntValue();

	if (value<=0)
		{
		JVM_Opcode_movePC(offset-3);
		}

	return(STCD_OK);
}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_if_icmpeq							Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.6			Status : Working   			*/
/*																						*/
/****************************************************************************************/


uint16_t JVM_cmd_if_icmpeq()
{
	int16_t offset;
	int32_t value1;
	int32_t value2;

	offset=JVM_Opcode_getCodeShort();

	value2=JVM_Opcode_popIntValue();
	value1=JVM_Opcode_popIntValue();

	if (value1==value2)
		{
		JVM_Opcode_movePC(offset-3);
		}

	return(STCD_OK);

}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_if_icmpne							Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.6			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_if_icmpne()
{
	int16_t offset;
	int32_t value1;
	int32_t value2;

	offset=JVM_Opcode_getCodeShort();

	value2=JVM_Opcode_popIntValue();
	value1=JVM_Opcode_popIntValue();

	if (value1!=value2)
		{
		JVM_Opcode_movePC(offset-3);
		}

	return(STCD_OK);

}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_if_icmplt							Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.4			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_if_icmplt()
{
	int16_t offset;
	int32_t value1;
	int32_t value2;

	offset=JVM_Opcode_getCodeShort();

	value2=JVM_Opcode_popIntValue();
	value1=JVM_Opcode_popIntValue();

	if (value1<value2)
		{
		JVM_Opcode_movePC(offset-3);
		}

	return(STCD_OK);

}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_if_icmpge							Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.4			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_if_icmpge()
{
	int16_t offset;
	int32_t value1;
	int32_t value2;

	offset=JVM_Opcode_getCodeShort();

	value2=JVM_Opcode_popIntValue();
	value1=JVM_Opcode_popIntValue();

	if (value1>=value2)
		{
		JVM_Opcode_movePC(offset-3);
		}

	return(STCD_OK);

}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_if_icmpgt							Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.4			Status : Working   			*/
/*																						*/
/****************************************************************************************/



uint16_t JVM_cmd_if_icmpgt()
{
	int16_t offset;
	int32_t value1;
	int32_t value2;

	offset=JVM_Opcode_getCodeShort();

	value2=JVM_Opcode_popIntValue();
	value1=JVM_Opcode_popIntValue();

	if (value1>value2)
		{
		JVM_Opcode_movePC(offset-3);
		}

	return(STCD_OK);

}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_if_icmple							Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.4			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_if_icmple()
{
	int16_t offset;
	int32_t value1;
	int32_t value2;

	offset=JVM_Opcode_getCodeShort();

	value2=JVM_Opcode_popIntValue();
	value1=JVM_Opcode_popIntValue();

	if (value1<=value2)
		{
		JVM_Opcode_movePC(offset-3);
		}

	return(STCD_OK);

}



/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_if_acmpeq							Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.15			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_if_acmpeq()
{
	int16_t offset;
	JVM_HandleNumber_t reference1;
	JVM_HandleNumber_t reference2;

	offset=JVM_Opcode_getCodeShort();

	reference2=JVM_Opcode_popReference();
	reference1=JVM_Opcode_popReference();

	// NEW return code for EXCEPTION -> NULL
	if (reference1 == 0 )
		return (STCD_NULL_REFERENCE);
	if (reference2 == 0 )
		return (STCD_NULL_REFERENCE);


	if (reference2==reference1)
		{
		JVM_Opcode_movePC(offset-3);
		}

	return(STCD_OK);
}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_if_acmpne							Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.16			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_if_acmpne()
{
	int16_t offset;
	JVM_HandleNumber_t reference1;
	JVM_HandleNumber_t reference2;

	offset=JVM_Opcode_getCodeShort();

	reference2=JVM_Opcode_popReference();
	reference1=JVM_Opcode_popReference();

	// NEW return code for EXCEPTION -> NULL
	if (reference1 == 0 )
		return (STCD_NULL_REFERENCE);
	if (reference2 == 0 )
		return (STCD_NULL_REFERENCE);

	if (reference2!=reference1)
		{
		JVM_Opcode_movePC(offset-3);
		}

	return(STCD_OK);
}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_goto									Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.6			Status : Working   			*/
/*																						*/
/****************************************************************************************/


uint16_t JVM_cmd_goto()
{

	int16_t offset;
	offset=JVM_Opcode_getCodeShort();

	return(JVM_Opcode_movePC(offset-3));
}



/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_jsr									Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.16			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_jsr()
{
	union data_value myData;

	myData.reference=JVM_Opcode_getPC()+2;

	JVM_Opcode_pushReference(myData.reference);
// TODO Push ReturnAdress !!!!
	return(JVM_cmd_goto());
}


/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_jsr_w								Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.4			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_jsr_w()
{
	return(STCD_OK);
}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_ret									Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.1.4			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_ret()
{
	return(STCD_OK);
}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_tableswitch							Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.2.2			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_tableswitch()
{
	uint16_t pc;
	int32_t index;
	uint16_t newAddress;


	int32_t defaultAddress;
	int32_t lowAddress;
	int32_t highAddress;

	newAddress=JVM_Opcode_getPC()-1;



	while ((JVM_Opcode_getPC()& 0x3) !=0)
		{
		JVM_Opcode_getCodeByte();
		}

	defaultAddress=JVM_Opcode_getCodeInt();
	lowAddress=JVM_Opcode_getCodeInt();
	highAddress=JVM_Opcode_getCodeInt();

	index=JVM_Opcode_popIntValue();


	if ((index<lowAddress) || (index>highAddress))
		{
		newAddress+=defaultAddress;
		}
	else
		{
		index=(index-lowAddress)*4;


		pc=JVM_Opcode_getPC();
		pc+=index;
		JVM_Opcode_setPC(pc);

		newAddress+=JVM_Opcode_getCodeInt();
		}
	JVM_Opcode_setPC(newAddress);



	//newAddress


	return(STCD_OK);
}

/****************************************************************************************/
/*																						*/
/*	Function : JVM_cmd_lookupswitch							Author : OG					*/
/*																						*/
/*	Description : 								   										*/
/*																						*/
/*	Version : 1.0					Date :2011.2.2			Status : Working   			*/
/*																						*/
/****************************************************************************************/

uint16_t JVM_cmd_lookupswitch()
{
	int32_t key;
	uint16_t newAddress;


	int32_t defaultAddress;
	int32_t tableSize;

	int32_t match;
	int32_t offset;

	newAddress=JVM_Opcode_getPC()-1;



	while ((JVM_Opcode_getPC()& 0x3) !=0)
		{
		JVM_Opcode_getCodeByte();
		}

	defaultAddress=JVM_Opcode_getCodeInt();
	tableSize=JVM_Opcode_getCodeInt()+1;

	key=JVM_Opcode_popIntValue();


	do{
		match=JVM_Opcode_getCodeInt();
		offset=JVM_Opcode_getCodeInt();
		tableSize--;
		}
	while ((match!=key) && (tableSize>0));

	if (tableSize==0)
		{
		newAddress+=defaultAddress;
		}
	else
		{
		newAddress+=offset;
		}

		JVM_Opcode_setPC(newAddress);
/*
	if ((index<lowAddress) || (index>highAddress))
		{
		newAddress+=defaultAddress;
		}
	else
		{
		index=(index-lowAddress)*4;


		pc=JVM_Opcode_getPC();
		pc+=index;
		JVM_Opcode_setPC(pc);

		newAddress+=JVM_Opcode_getCodeInt();
		}
	JVM_Opcode_setPC(newAddress);

*/

	//newAddress


	return(STCD_OK);
}

